package config

import (
	"fmt"
	"gopkg.in/yaml.v3"
	"os"
	"reflect"
	"strconv"
)

type Model struct {
	Name         string           `yaml:"name" env:"NAME"`
	Http         http             `yaml:"http"`
	Log          log              `yaml:"log"`
	DB           map[string]dbEle `yaml:"db"`
	WebServerLog WebServerLog     `yaml:"webServerLog"`
	Redis        map[string]Redis `yaml:"redis"`
}

func (m *Model) LoadConfig(configPath string) error {
	//找到 运行换行配置文件路径
	//根据配置文件路径加载 内容
	//考虑环境变量重载 和 刷新
	configDef := configPath + "/configs/config-default.yml"
	configOverride := configPath + "/configs/config.yml"
	err := m.parseConfig(configDef)
	if err != nil {
		return err
	}
	err = m.parseConfig(configOverride)
	if err != nil {
		return err
	}
	//重载环境变量
	m.mergeEnv()

	return nil
}

// parseConfig 处理 yml 配置文件
func (m *Model) parseConfig(config string) error {
	data, err := os.ReadFile(config)
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(data, &m)
	if err != nil {
		return err
	}
	return nil
}

// MergeEnv 获取环境变量
func (m *Model) mergeEnv() {
	assign(reflect.ValueOf(m))
}

// 获取环境变量
// 其实这里可以 直接获取命令行 参数就行就能区分运行环境
func assign(val reflect.Value) {
	ele := reflect.Indirect(val)
	for i := 0; i < ele.NumField(); i++ {
		key := ele.Type().Field(i).Tag.Get("env")
		processOne(ele.Field(i), key)
	}
}

func processOne(field reflect.Value, key string) {
	//获命令行参数
	envValue, ok := os.LookupEnv(key)
	fmt.Println("ok ", ok, " envValue ", envValue, " key ", key)
	if ok {
		switch field.Kind() {
		case reflect.String:
			field.SetString(envValue)
		case reflect.Bool:
			value, err := strconv.ParseBool(envValue)
			if err != nil {
				return
			}
			field.SetBool(value)
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			value, err := strconv.ParseInt(envValue, 0, field.Type().Bits())
			if err != nil {
				return
			}
			field.SetInt(value)
		case reflect.Float32, reflect.Float64:
			value, err := strconv.ParseFloat(envValue, field.Type().Bits())
			if err != nil {
				return
			}
			field.SetFloat(value)

		case reflect.Struct:
			assign(field)

			//逗号分割的数组
		case reflect.Slice:

		default:
			panic("unhandled default case")
		}
	}
}
